home *** CD-ROM | disk | FTP | other *** search
- /*
- * Convert date and time data formats.
- *
- * tm_to_time(tm) convert tm struct to seconds since 1/1/70
- * time_to_tm(tp) convert seconds since 1/1/70 to tm struct
- * get_time() return current time in seconds since 1/1/70
- * set_tzone() figure out current timezone (config.tzone)
- */
-
- #include <stdio.h>
- #if defined(MIPS) || defined(NEWSOS4)
- #include <sys/types.h>
- #endif
- #include <time.h>
- #include <X11/StringDefs.h>
- #include "conf.h"
-
- #undef DEBUG /* define this to debug timezone calc */
-
- extern char *getenv();
- extern void get_rsrc();
- extern struct config config; /* global configuration data */
-
- short monthlen[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- short monthbegin[12] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
-
-
- /*
- * convert a tm structure (d.m.y h:m:s) to a time in seconds since 1/1/70.
- * The difference to mktime() is that the result modulo 86400 is always
- * the time, regardless of timezones and daylight saving time. This makes
- * it much easier to process days with different DST status.
- * This routine only works correctly for the range 1970..2069.
- */
-
- time_t tm_to_time(tm)
- struct tm *tm; /* time/date to convert */
- {
- time_t t; /* return value */
-
- t = monthbegin[tm->tm_mon] /* full months */
- + tm->tm_mday-1 /* full days */
- + (!(tm->tm_year & 3) && tm->tm_mon > 1); /* leap day this year*/
- tm->tm_yday = t;
- t += 365 * (tm->tm_year - 70) /* full years */
- + (tm->tm_year - 69)/4; /* past leap days */
- tm->tm_wday = (t + 4) % 7;
-
- t = t*86400 + tm->tm_hour*3600 + tm->tm_min*60 + tm->tm_sec;
- if (tm->tm_mday > monthlen[tm->tm_mon] +
- (!(tm->tm_year & 3) && tm->tm_mon == 1))
- return((time_t)-1);
- return(t);
- }
-
-
- /*
- * convert time in seconds since 1/1/70 to a tm structure, and also fill in
- * the week number, julian date, and weekday. The difference to localtime()
- * is that timezones and daylight saving time are ignored.
- * This routine only works correctly for the range 1970..2069.
- */
-
- struct tm *time_to_tm(t)
- time_t t; /* time to convert */
- {
- int n, l; /* temp */
- static struct tm tm; /* returned tm */
-
- tm.tm_sec = t % 60; t /= 60;
- tm.tm_min = t % 60; t /= 60;
- tm.tm_hour = t % 24; t /= 24;
- tm.tm_wday = (t + 4) % 7;
-
- n = t / (365+365+366+365);
- tm.tm_year = 70 + n*4; t -= n * (365+365+366+365);
- if (t > 364) tm.tm_year++, t -= 365;
- if (t > 364) tm.tm_year++, t -= 365;
- if (t > 365) tm.tm_year++, t -= 366;
- tm.tm_yday = t;
-
- for (n=0; n < 11; n++) {
- l = monthlen[n] + (n==1 && !(tm.tm_year&3));
- if (t < l)
- break;
- t -= l;
- }
- tm.tm_mon = n;
- tm.tm_mday = t+1;
- return(&tm);
- }
-
-
- /*
- * return current time in seconds since 1/1/70. The timezone is applied
- * such that the return value modulo 86400 is the number of seconds since
- * midnight.
- */
-
- time_t get_time()
- {
- return(time(0) - config.tzone + config.adjust_time);
- }
-
-
- /*
- * return the current time zone as the number of seconds as difference
- * to GMT (UTC) in seconds. Since all the tricks with tm_isdst, gmtoff,
- * _timezone etc turned out to be nonportable, I am now parsing the TZ
- * environment variable directly. There is nothing standard about standard
- * libraries when it comes to time calculation!
- */
-
- void set_tzone()
- {
- register struct config *c = &config;
- time_t now; /* current local time */
- time_t tod; /* time-of-day, 0..86399 */
- struct tm *tm; /* julian date of <now> */
-
- now = time(0) - c->raw_tzone;
- tod = now % 86400;
- tm = time_to_tm(now);
- switch(c->dst_flag) {
- case 0: /* dst on */
- c->tzone = c->raw_tzone - 3600;
- break;
- case 1: /* dst off */
- c->tzone = c->raw_tzone;
- break;
- case 2: /* auto dst */
- if ((tm->tm_yday > c->dst_begin ||
- tm->tm_yday == c->dst_begin && tod >= c->dst_begin_time)&&
- (tm->tm_yday == c->dst_end && tod < c->dst_end_time ||
- tm->tm_yday < c->dst_end))
- c->tzone = c->raw_tzone - 3600;
- else
- c->tzone = c->raw_tzone;
- }
- }
-
-
- /*
- * Figure out reasonable values for the config fields raw_tzone, dst_flag,
- * dst_begin, and dst_end. This is used for defaults if the .dayplan file
- * does not specify the adjustment, or when the user presses Guess in the
- * Adjust Time popup.
- */
-
- #define DST_BEGIN 64 /* default begin of DST */
- #define DST_END 220 /* default end of DST */
-
- #ifdef DEBUG
- static char *zone_time_string();
- #endif
- static get_zone_time();
-
- guess_tzone()
- {
- char *tz=0; /* timezone string (TZ) */
- int zone=0, dst= -3600; /* difference from GMT */
- int begin=0, begintime=0; /* dst begin: julian day/time*/
- int end=0, endtime=0; /* dst end: julian day/time */
-
- if (((tz = getenv("PLAN_TZ")) && *tz ||
- (tz = getenv("TZ")) && *tz) && strrchr("0123456789-",tz[3])){
- do {
- if (!*tz++ || !*tz++ || !*tz++) /* MET */
- break;
- zone = get_zone_time(&tz, 0); /* time */
- dst = zone - 3600;
- if (!*tz++ || !*tz++ || !*tz++) /* MST */
- break;
- dst = get_zone_time(&tz, dst); /* time */
- if (*tz++ != ';') /* ;begin */
- break;
- while (*tz >= '0' && *tz <= '9')
- begin = begin*10 + *tz++ - '0';
- if (*tz == '/') { /* /time */
- tz++;
- begintime = get_zone_time(&tz, 0);
- }
- if (*tz++ != ',') /* ,end */
- break;
- while (*tz >= '0' && *tz <= '9')
- end = end*10 + *tz++ - '0';
- if (*tz++ == '/') /* /time */
- endtime = get_zone_time(&tz, 0);
- } while (0);
- } else {
- #if defined(SVR4) || defined(SOLARIS2)
- time_t now = get_time();
- struct tm *tm = localtime(&now);
- time_t h = tm->tm_hour;
- struct tm *gmt = gmtime(&now);
- zone = (gmt->tm_hour - h) * 3600;
- dst = zone - 3600;
- #else
- #if defined(bsdi) || defined(SUN) || defined(SVR4)
- time_t now;
- struct tm *tm;
- tzset();
- now = time(0);
- tm = localtime(&now);
- zone = -tm->tm_gmtoff;
- #endif
- #endif
- }
- #ifdef DEBUG
- if (tz = getenv("PLAN_TZ"))
- printf("PLAN_TZ env variable: %s\n", tz);
- if (tz = getenv("TZ"))
- printf("TZ env variable: %s\n", tz);
- printf("standard timezone: GMT%s\n", zone_time_string(zone));
- printf("DST timezone: GMT%s\n", zone_time_string(dst));
- printf("DST start: %s on julian day %d\n",
- zone_time_string(begintime)+1, begin);
- printf("DST end: %s on julian day %d\n",
- zone_time_string(endtime)+1, end);
- #endif
- if (!begin) { /* defaults */
- begin = DST_BEGIN;
- begintime = 2*3600;
- }
- if (!end) {
- end = DST_END;
- endtime = 2*3600;
- }
- config.raw_tzone = zone;
- config.dst_flag = 2;
- config.dst_begin = begin;
- config.dst_end = end;
- config.dst_begin_time = begintime;
- config.dst_end_time = endtime;
- #ifdef DEBUG
- printf("current timezone: GMT%s\n", zone_time_string(zone));
- #endif
- }
-
-
- /*
- * parse a time string of the form [hours[:minutes[:seconds]]], return seconds
- */
-
- static get_zone_time(tzp, zdefault)
- char **tzp;
- int zdefault;
- {
- char *tz = *tzp;
- int i, num, zone = 0;
- int sign = 1;
-
- if (*tz == '-') tz++, sign = -1;
- if (*tz == '+') tz++;
- for (i=0; i < 3; i++) {
- zone *= 60;
- num = 0;
- while (*tz >= '0' && *tz <= '9')
- num = num*10 + *tz++ - '0';
- zone += num;
- tz += *tz == ':';
- }
- zone *= sign;
- if (tz == *tzp)
- zone = zdefault;
- *tzp = tz;
- return(zone);
- }
-
-
- /*
- * return a number of seconds as a string "+/-hours:minutes:seconds"
- */
-
- #ifdef DEBUG
- static char *zone_time_string(t)
- int t;
- {
- static char buf[12];
-
- t %= 86400;
- buf[0] = t < 0 ? '-' : '+';
- if (t < 0)
- t = -t;
- sprintf(buf+1, "%02d:%02d:%02d", t/3600, (t/60)%60, t%60);
- return(buf);
- }
- #endif
-